//
//  LockTest.swift
//  EasySwift
//
//  Created by 王隆帅 on 2017/7/6.
//  Copyright © 2017年 王隆帅. All rights reserved.
//

import UIKit

class LockTest: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Do any additional setup after loading the view.
        
        view.backgroundColor = UIColor.red;
        testNSContionLock();
    }
    
    func testNSDistributedLock() {
        
        // mac 下开发 略过 
        // 上多个进程或多个程序之间
    }
    
    func testNSContionLock() {
        
        let lockObject = LockObject.init();
        
        let conditionLock = NSConditionLock();
        
        DispatchQueue.global().async {
            
            for index in 1...2 {
                
                conditionLock.lock();
                sleep(2);
                lockObject.saveSomethingToLockObject(saveObject: "1");
                sleep(3);
                
                conditionLock.unlock(withCondition: index);
            }
            
            //            for index in 1...4 {
            //
            //                conditionLock.lock();
            //                sleep(2);
            //                lockObject.saveSomethingToLockObject(saveObject: "1");
            //                sleep(3);
            //
            //                conditionLock.unlock(withCondition: index);
            //            }
            
        }
        
        DispatchQueue.global().async {
            
            sleep(1);
            conditionLock.lock(whenCondition: 2);
            print(lockObject.deleteSomethingFromLockObject(deleteObject: "1")) ;
            conditionLock.unlock();
            
            //            sleep(1);
            //
            //            let isLock = conditionLock.tryLock(whenCondition: 2);
            //
            //            print(lockObject.deleteSomethingFromLockObject(deleteObject: "1")) ;
            //
            //            if isLock {
            //
            //                conditionLock.unlock();
            //            }
            
        }
        
    }
    
    /**
     ，NSRecursiveLock 类定义的锁可以在同一线程多次 lock，而不会造成死锁。递归锁会跟踪它被多少次 lock。每次成功的 lock 都必须平衡调用 unlock 操作。只有所有的锁住和解锁操作都平衡的时候，锁才真正被释放给其他线程获得。
     */
    func testNSRecursiveLock() {
        
        let lockObject = LockObject.init();
        
        let recursiveLock = NSRecursiveLock();
        
        DispatchQueue.global().async {
            
            typealias recursiveFunc2 = (Int) -> Void
            
            var recursiveFunc1: recursiveFunc2?;
            
            recursiveFunc1 = {indexObject in
                
                recursiveLock.lock();
                
                if indexObject > 0 {
                    
                    sleep(2);
                    lockObject.saveSomethingToLockObject(saveObject: "1");
                    sleep(3);
                    
                    recursiveFunc1!(indexObject - 1);
                }
                
                recursiveLock.unlock();
                
            };
            
            recursiveFunc1!(5);
        }
        
        DispatchQueue.global().async {
            
            sleep(1);
            recursiveLock.lock();
            print(lockObject.deleteSomethingFromLockObject(deleteObject: "1")) ;
            recursiveLock.unlock();
        }
    }
    
    func testSemaphore() {
        
        let lockObject = LockObject.init()
        
        let semaphore = DispatchSemaphore.init(value: 1);
        
        DispatchQueue.global().async {
            
            // 降低信号量
            semaphore.wait();
            sleep(2);
            lockObject.saveSomethingToLockObject(saveObject: "1");
            sleep(3);
            // 提高信号量
            semaphore.signal();
        }
        
        DispatchQueue.global().async {
            
            sleep(1);
            // 降低信号量
            semaphore.wait();
            print(lockObject.deleteSomethingFromLockObject(deleteObject: "1")) ;
            // 提高信号量
            semaphore.signal();
        }
    }
    
    func testSynchronized() {
        
        let lockObject = LockObject.init()
        
        DispatchQueue.global().async {
            
            objc_sync_enter(lockObject)
            sleep(2);
            lockObject.saveSomethingToLockObject(saveObject: "1");
            sleep(3);
            objc_sync_exit(lockObject)
        }
        
        DispatchQueue.global().async {
            
            sleep(1);
            objc_sync_enter(lockObject)
            print(lockObject.deleteSomethingFromLockObject(deleteObject: "1")) ;
            objc_sync_exit(lockObject)
        }
    }
    
    func testNSLock() {
        
        let lockObject = LockObject.init()
        let lock = NSLock.init();
        
        DispatchQueue.global().async {
            
            lock.lock();
            sleep(2);
            lockObject.saveSomethingToLockObject(saveObject: "1");
            sleep(3);
            lock.unlock();
        }
        
        DispatchQueue.global().async {
            
            sleep(1);
            lock.lock();
            print(lockObject.deleteSomethingFromLockObject(deleteObject: "1")) ;
            lock.unlock();
        }
        
    }
    
    func testNormal() {
        
        let lockObject = LockObject.init()
        
        DispatchQueue.global().async {
            
            sleep(2);
            lockObject.saveSomethingToLockObject(saveObject: "1");
            sleep(3);
        }
        
        DispatchQueue.global().async {
            
            sleep(1);
            print(lockObject.deleteSomethingFromLockObject(deleteObject: "1")) ;
            
        }
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    
    /*
     // MARK: - Navigation
     
     // In a storyboard-based application, you will often want to do a little preparation before navigation
     override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
     // Get the new view controller using segue.destinationViewController.
     // Pass the selected object to the new view controller.
     }
     */
    
}
